﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using System.ComponentModel;
using System.Data.SqlClient;
using System.Xml.Serialization;

namespace Nizm0.QOT.Library.Objects
{
    [Serializable]
    public class Server : Objects.ISettingsObjects, IXmlSerializable
    {
        public static int _instancji = 0;
        public static int _lastid = 0;

        private int _id;
        private string _name;
        private string _address;
        private bool _sspi;
        private string _login;
        private string _password;
        private DataBase _actualDatabase = new DataBase("master");
        private bool _useInThisProject;

        private string _conStr;

        //private List<Table> _tables = new List<Table>();
        private List<DataBase> _dataBaseList;
        private TypeOfServer _type = TypeOfServer.NoUsed;

        private bool _connectionEstablished = false;
        private bool _alreadyTriedToConnect = false;

        private int _treeLewel = 0;
        private bool _checked = false;
        private object _parent;

        [Flags]
        public enum TypeOfServer { NoUsed = 0x0, TestServer = 0x1, SourceServer = 0x2, ProfilerServer = 0x4 }
        public enum LoginType { WindowsAuthentication = 0, SQLServerAuthentication }

        #region Delegates

        //public delegate void OnServerChange(Object sender, EventArgs e);
        public delegate void OnServerChange(Object sender);
        public event OnServerChange DataBaseChange;

        public delegate void BoolValueChange(Server server);
        public event BoolValueChange UseInThisProjectValueChange;

        public static event ChangeStatusEvetHendler StatusChange;

        public static event ErrorEventHandler ErrorEvent;

        public static void SetStatusChangeEvent(ChangeStatusEvetHendler test)
        {
            if (StatusChange == null)
                StatusChange += test;
        }

        public static void SetErrorEvent(ErrorEventHandler test)
        {
            if (ErrorEvent == null)
                ErrorEvent += test;
        }
        #endregion

        #region Propertiess
        [CategoryAttribute("Misc"), ReadOnlyAttribute(true)]
        public int ID
        {
            get { return _id; }
            set { _id = value; }
        }
        [CategoryAttribute("Additional Info")]
        public string Name
        {
            get
            {
                if (string.IsNullOrWhiteSpace(_name))
                    _name = _address;
                return _name; }
            set { _name = value; }
        }
        [CategoryAttribute("Additional Info"), ReadOnlyAttribute(true)]
        public string Address
        {
            get { return _address; }
            set { _address = value; }
        }
        [CategoryAttribute("Additional Info")]
        public bool SSPI
        {
            get { return _sspi; }
            set { _sspi = value; }
        }
        [CategoryAttribute("Additional Info")]
        public string Login
        {
            get { return _login; }
            set { _login = value; }
        }
        [PasswordPropertyText(true),
        CategoryAttribute("Additional Info")]
        public string Password
        {
            get { return _password; }
            set { _password = value; }
        }
        /*
        public int Queries
        {
            get { return _queries; }
            set { _queries = value; }
        }
        */
        [CategoryAttribute("Additional Info")]
        public List<DataBase> DataBase
        {
            get { return _dataBaseList; }
            set
            {
                _dataBaseList = value;
                if (DataBaseChange != null)
                    DataBaseChange(value);
            }
        }
        [CategoryAttribute("Additional Info")]
        public DataBase ActualDataBase
        {
            get { return _actualDatabase; }
            set { _actualDatabase = value; }
        }
        [CategoryAttribute("Additional Info")]
        public bool UseInThisProject
        {
            get { return _useInThisProject; }
            set
            {
                _useInThisProject = value;
                if (UseInThisProjectValueChange != null)
                    UseInThisProjectValueChange(this);
            }
        }
        [BrowsableAttribute(false)]
        public string ConectionString
        {
            get
            {
                //if (_conStr == "" || _conStr == null)
                return UpdateConectionString();
                //else
                //    return _conStr;
            }
            //set { _conStr = value; }
        }
        [CategoryAttribute("Additional Info"), ReadOnlyAttribute(true)]
        public bool ConnectionEstablished
        {
            get
            {
                lock (this)
                {
                    if (_useInThisProject)
                    {
                        if (!_connectionEstablished && _alreadyTriedToConnect)
                        {
                            _connectionEstablished = false;
                            return _connectionEstablished;
                        }
                        else
                        {
                            if (!_connectionEstablished)
                            {
                                _connectionEstablished = Library.Scripts.GetFromSQL.TestConnectionToSQL(this);
                                _alreadyTriedToConnect = true;
                            }
                            return _connectionEstablished;
                        }
                    }
                    else
                    {
                        _connectionEstablished = false;
                        return _connectionEstablished;
                    }
                }
            }
            //set { _connectionestablished = value; }
        }
        [CategoryAttribute("Additional Info"), ReadOnlyAttribute(true)]
        public bool AlreadyTriedToConnect
        {
            get { return _alreadyTriedToConnect; }
            //set { _alreadytriedtoconnect = value; }
        }
        [CategoryAttribute("Misc"), ReadOnlyAttribute(true)]
        public object Parent
        {
            get { return _parent; }
            set { _parent = value; }
        }
        [CategoryAttribute("Misc"), ReadOnlyAttribute(true)]
        public TypeOfServer Type
        {
            get { return _type; }
            set
            {
                _type = value;
            }
        }
        #endregion

        #region Objects.ISettingsObjects Members

        public int Treelevel
        {
            get
            {
                return _treeLewel;
            }
        }


        public bool Checked
        {
            get
            {
                return _checked;
            }
            set
            {
                _checked = value;
            }
        }
        #endregion

        //public string DateStart
        //{
        //    get { return _datestart; }
        //    set { _datestart = value; }
        //}
        //public string DateStop
        //{
        //    get { return _datestop; }
        //    set { _datestop = value; }
        //}
        /*
        public override string ToString()
        {
            return _address;
        }
        */

        #region Constructors
        public Server(int ID, string Address, bool SSPI, string Login, string Password, List<DataBase> DataBase)
        {
            _instancji++;

            this._id = ID;
            this._address = Address;
            this._sspi = SSPI;
            this._login = Login;
            this._password = Password;
            this._dataBaseList = DataBase;
            if (Server._lastid <= _id)
                Server._lastid = _id;
        }
        public Server(int ID, string Address, bool SSPI, string Login = null, string Password = null)
        {
            _instancji++;

            this._id = ID;
            this._address = Address;
            this._sspi = SSPI;
            this._login = Login;
            this._password = Password;
            if (Server._lastid <= _id)
                Server._lastid = _id;
        }
        /*
        public ProfilerServer(int ID, string Address, bool SSPI, string login, string Password, int Queries, string database, Dictionary<string, Table> ListaTabel, Dictionary<string, ProcedureResultInformation> procedures)
        {
            _instancji++;

            this._id = ID;
            this._address = Address;
            this._sspi = SSPI;
            this._login = login;
            this._password = Password;
            this._queries = Queries;
            this._databaselist = database;
            this._tables = ListaTabel;
            this._procedures = procedures;
            if (ProfilerServer._lastid <= _id)
                ProfilerServer._lastid = _id;
        }
        public ProfilerServer(int ID, string Address, bool SSPI, string login, string Password, int Queries, string database)
        {
            _instancji++;

            this._id = ID;
            this._address = Address;
            this._sspi = SSPI;
            this._login = login;
            this._password = Password;
            this._queries = Queries;
            this._databaselist = database;
            if (ProfilerServer._lastid <= _id)
                ProfilerServer._lastid = _id;
        }
        */
        public Server(int ID, string Address)
        {
            _instancji++;

            this._id = ID;
            this._address = Address;
            this._dataBaseList = new List<DataBase>();
            if (Server._lastid <= _id)
                Server._lastid = _id;

        }
        public Server(string Address)
        {
            _instancji++;

            this._id = _lastid + 1;
            this._address = Address;
            this._dataBaseList = new List<DataBase>();
            if (Server._lastid <= _id)
                Server._lastid = _id;

        }
        public Server()
        {
            _instancji++;

            this._dataBaseList = new List<DataBase>();
            //this._serveradress = new ArrayList();
            //this._tabeledoprzeszukania = new ArrayList();
        }
        ~Server()
        {
            _instancji--;
            //throw new Exception("Destruktor ProfilerServer");

        }
        #endregion

        public bool ForceCheckConnection()
        {
            lock (this)
            {
                _connectionEstablished = Library.Scripts.GetFromSQL.TestConnectionToSQL(this);
                _alreadyTriedToConnect = true;
                return _connectionEstablished;
            }
        }

        public string UpdateConectionString()
        {
            //string conectionstring;
            //if (_sspi == false)
            //{
            //    conectionstring = "Data source=" +
            //        _address + ";user id=" + _login +
            //        "; password=" + _password + "; Database=" + _actualdatabase.Name +
            //        "; Connection Timeout=" + Library.Settings.Instance.CommandTimeout +
            //        "; App=" + Settings.AssemblyProduct;
            //}
            //else
            //{
            //    conectionstring = "Data source=" +
            //        _address + ";Integrated Security = SSPI" + "; Database=" + _actualdatabase.Name +
            //        "; Connection Timeout=" + Library.Settings.Instance.CommandTimeout +
            //        "; App=" + Settings.AssemblyProduct;
            //}
            //_conStr=conectionstring;
            return UpdateConectionString(_actualDatabase);
        }
        public string UpdateConectionString(DataBase database)
        {
            //string conectionstring;
            //if (_sspi == false)
            //{
            //    conectionstring = "Data source=" +
            //        _address + ";user id=" + _login +
            //        "; password=" + _password + "; Database=" + database.Name +
            //        "; Connection Timeout=" + Library.Settings.Instance.CommandTimeout +
            //        "; App=" + Settings.AssemblyProduct;
            //}
            //else
            //{
            //    conectionstring = "Data source=" +
            //        _address + ";Integrated Security = SSPI" + "; Database=" + database.Name +
            //        "; Connection Timeout=" + Library.Settings.Instance.CommandTimeout +
            //        "; App=" + Settings.AssemblyProduct;
            //}
            _conStr = GetConnectionString(database);
            return _conStr;
        }

        public string GetConnectionString()
        {
            return GetConnectionString(_actualDatabase, Settings.Instance.CommandTimeout);
        }
        public string GetConnectionString(DataBase database)
        {
            return GetConnectionString(database, Settings.Instance.CommandTimeout);
        }
        public string GetConnectionString(int timeout)
        {
            return GetConnectionString(_sspi, _actualDatabase.Name, timeout);
        }
        public string GetConnectionString(bool sspi, int timeout)
        {
            return GetConnectionString(sspi, _actualDatabase.Name, timeout);
        }
        public string GetConnectionString(int timeout, string login, string password)
        {
            return GetConnectionString(_actualDatabase.Name, timeout, login, password);
        }
        public string GetConnectionString(DataBase database, int timeout)
        {
            return GetConnectionString(_sspi, database.Name, timeout);
            //string conectionstring;
            //if (_sspi == false)
            //{
            //    conectionstring = "Data source=" +
            //        _address + ";user id=" + _login +
            //        "; password=" + _password + "; Database=" + database.Name +
            //        "; Connection Timeout=" + timeout +
            //        "; App=" + Settings.Instance.AssemblyProduct;
            //}
            //else
            //{
            //    conectionstring = "Data source=" +
            //        _address + ";Integrated Security = SSPI" + "; Database=" + database.Name +
            //        "; Connection Timeout=" + timeout +
            //        "; App=" + Settings.Instance.AssemblyProduct;
            //}
            ////_conStr = conectionstring;
            //return conectionstring;
        }
        public string GetConnectionString(string database)
        {
            return GetConnectionString(_sspi, database, Settings.Instance.CommandTimeout);
        }
        public string GetConnectionString(bool sspi, string database, int timeout)
        {
            return sspi ? "Data source=" +
                    _address + ";Integrated Security = SSPI" + "; Initial Catalog=" + database +
                    "; Connection Timeout=" + timeout +
                    "; App=" + Settings.Instance.AssemblyProduct : GetConnectionString(database, timeout, _login, _password);
        }
        public string GetConnectionString(string database, int timeout, string login, string password)
        {
            //string conectionstring;
            //if (_sspi == false)
            //{
            //conectionstring = "Data source=" +
            //    _address + ";user id=" + login +
            //    "; password=" + password + "; Initial Catalog=" + database +
            //    "; Connection Timeout=" + timeout +
            //    "; App=" + Settings.Instance.AssemblyProduct;
            //}
            //else
            //{
            //    conectionstring = "Data source=" +
            //        _address + ";Integrated Security = SSPI" + "; Initial Catalog=" + database +
            //        "; Connection Timeout=" + timeout +
            //        "; App=" + Settings.Instance.AssemblyProduct;
            //}
            //_conStr = conectionstring;
            return "Data source=" +
                    _address + ";user id=" + login +
                    "; password=" + password + "; Initial Catalog=" + database +
                    "; Connection Timeout=" + timeout +
                    "; App=" + Settings.Instance.AssemblyProduct; ;
        }

        public SqlConnection GetSqlConnection(int timeout)
        {
            SqlConnection con;
            try
            {
                con = new SqlConnection(GetConnectionString(timeout));
                con.Open();
                return con;
            }
            catch (SqlException ex)
            {
                switch (ex.Number)
                {
                    case 53:
                        {
#if DEBUG
                            MessageBox.Show("Server not found" + Environment.NewLine + ex.Message, "Wharning");
#endif
                            OnErrorEventMethod(this, ex);
                            return null;
                        }
                    case 18452:
                        {
#if DEBUG
                            MessageBox.Show("Login: " + this._login + " nod exist" + Environment.NewLine + ex.Message, "Wharning");
#endif
                            OnErrorEventMethod(this, ex);
                            Forms.SqlConnectionProblem f = new Forms.SqlConnectionProblem("Login: " + this._login + " nod exist", this);
                            f.ShowDialog();
                            return f.con;
                        }
                    case 18456:
                        {
#if DEBUG
                            MessageBox.Show("Login faild for user: " + this._login + Environment.NewLine + ex.Message, "Wharning");
#endif
                            OnErrorEventMethod(this, ex);
                            Forms.SqlConnectionProblem f = new Forms.SqlConnectionProblem("Login faild for user: " + this._login, this);
                            f.ShowDialog();
                            return f.con;
                        }
                    default:
                        {
                            OnErrorEventMethod(this, ex);
                            return null;
                        }
                }
                //return GetSqlConnection(database, timeout);
            }
        }

        public void UpdateTable(List<Table> ListOfTable, ListBox.SelectedObjectCollection ListOfSelectetNameOfTable)
        {
            ArrayList ArrayListOfTable = new ArrayList();
            ArrayList ArrayListOfSelectedNameOfTable = new ArrayList();

            foreach (Table tmpTable in ListOfTable)
            {
                ArrayListOfTable.Add(tmpTable.Name);
            }
            foreach (string tmpName in ListOfSelectetNameOfTable)
            {
                ArrayListOfSelectedNameOfTable.Add(tmpName);
            }

            foreach (string tmpName in ArrayListOfSelectedNameOfTable)
            {
                if (ArrayListOfTable.Equals(tmpName))
                {
                    ArrayListOfTable.IndexOf(tmpName);

                }
            }

        }

        /// <summary>
        /// please do not use it
        /// </summary>
        /// <param name="databases"></param>
        public void MargeDataBases(List<DataBase> databases)
        {
            foreach (DataBase tmpdatabase in databases)
            {
                if (_dataBaseList.Exists(d => d.Name == tmpdatabase.Name))
                {
                    if (_dataBaseList.Find(d => d.Name == tmpdatabase.Name).Checked || tmpdatabase.Checked) _dataBaseList.Find(d => d.Name == tmpdatabase.Name).Checked = true; else _dataBaseList.Find(d => d.Name == tmpdatabase.Name).Checked = false;
                    _dataBaseList.Find(d => d.Name == tmpdatabase.Name).MargeProcedures(tmpdatabase.Procedures);
                    _dataBaseList.Find(d => d.Name == tmpdatabase.Name).MargeTables(tmpdatabase.Tables);
                }
                else
                {
                    _dataBaseList.Add(tmpdatabase);
                }
            }

        }

        public void Marge(Server server)
        {
            if (_checked || server.Checked)
                _checked = true;
            else
                _checked = false;
            if (_useInThisProject || server.UseInThisProject)
                _useInThisProject = true;
            else
                _useInThisProject = false;
            foreach (DataBase tmpdatabase in server._dataBaseList)
            {
                if (_dataBaseList.Exists(d => d.Name == tmpdatabase.Name))
                {
                    _dataBaseList.Find(d => d.Name == tmpdatabase.Name).Marge(tmpdatabase);
                }
                else
                {
                    _dataBaseList.Add(tmpdatabase);
                }
            }
        }
        /// <summary>
        /// If true leave settings unchanged, if false set settigs from marged object
        /// </summary>
        /// <param name="server"></param>
        /// <param name="left"></param>
        public void Marge(Server server, bool left)
        {
            if (_checked || server.Checked)
                _checked = true;
            else
                _checked = false;
            if (!left)
            {
                _useInThisProject = server.UseInThisProject;
                _sspi = server.SSPI;
                _login = server.Login;
                _password = server.Password;
                _parent = server.Parent;
                _type = server.Type;
            }

            foreach (DataBase tmpdatabase in server._dataBaseList)
            {
                if (_dataBaseList.Exists(d => d.Name == tmpdatabase.Name))
                {
                    _dataBaseList.Find(d => d.Name == tmpdatabase.Name).Marge(tmpdatabase);
                }
                else
                {
                    _dataBaseList.Add(tmpdatabase);
                }
            }
        }

        public override string ToString()
        {
            return Name;
        }

        private void OnErrorEventMethod(object sender, Exception ex)
        {
            if (ErrorEvent != null) ErrorEvent(sender, ex);
        }
        private void OnStatusChangeEventMethod(string str)
        {
            if (StatusChange != null) StatusChange(str);
        }

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            throw new NotImplementedException();
        }

        public void ReadXml(System.Xml.XmlReader reader)
        {
            reader.MoveToContent();

            _name = reader.GetAttribute("Name");
            _address = reader.GetAttribute("Address");
            Boolean.TryParse(reader.GetAttribute("Checked"), out _checked);
            Boolean.TryParse(reader.GetAttribute("UseInThisProject"), out _useInThisProject);
            Boolean.TryParse(reader.GetAttribute("SSPI"), out _sspi);
            Enum.TryParse<TypeOfServer>(reader.GetAttribute("Type"), out _type);
            if (!_sspi)
            {
                _login = reader.GetAttribute("Login");
                _password = reader.GetAttribute("Password");
            }
            System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
            doc.LoadXml(reader.ReadInnerXml());

            foreach (System.Xml.XmlNode node in doc.ChildNodes)
            {
                System.Xml.XmlReader r = new System.Xml.XmlNodeReader(node);

                System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(DataBase));//Type.GetType(className));
                var obj = (DataBase)Convert.ChangeType(serializer.Deserialize(r), typeof(DataBase));//Type.GetType(className));
                obj.Parent = this;
                _dataBaseList.Add(obj);
            }
        }

        public void WriteXml(System.Xml.XmlWriter writer)
        {
            writer.WriteAttributeString("Name", _name);
            writer.WriteAttributeString("Address", _address.ToString());
            writer.WriteAttributeString("Checked", _checked.ToString());
            writer.WriteAttributeString("UseInThisProject", _useInThisProject.ToString());
            writer.WriteAttributeString("SSPI", _sspi.ToString());
            writer.WriteAttributeString("Type", _type.ToString());
            if (!_sspi)
            {
                if (this.Login != null)
                {
                    writer.WriteAttributeString("Login", _login.ToString());
                    writer.WriteAttributeString("Password", _password.ToString());
                }
            }
            foreach (DataBase db in _dataBaseList)
            {
                if (db.Checked)
                {
                    var nsSerializer = new XmlSerializerNamespaces();
                    nsSerializer.Add("", "");
                    System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serialization.XmlSerializer(db.GetType(), "");
                    xmlSerializer.Serialize(writer, db, nsSerializer);
                }
            }
        }
    }
}
